using System;
using System.Collections.Generic;
using System.Text;

namespace TXLooker.Common.Core
{
    public abstract class SelfUpdater : /*MarshalByRefObject,*/ IDisposable
    {
        private System.Threading.Timer m_timer = null;

        public TimeSpan UpdatePeriod
        {
            get { return this.m_updatePeriod;  }
            set 
            {
                if( this.m_updatePeriod == value )
                    return;

                this.m_updatePeriod = value;

                this.RaiseRefreshPeriodChanged();
            }
        }
        private TimeSpan m_updatePeriod = new TimeSpan( 0, 0, 30 );

        public event EventHandler UpdatePeriodChanged
        {
            add    { lock( m_syncUpdatePeriod ) { this.m_UpdatePeriodChangedEH += value; } }
            remove { lock( m_syncUpdatePeriod ) { this.m_UpdatePeriodChangedEH -= value; } }
        }
        private EventHandler m_UpdatePeriodChangedEH = null;
        private readonly object m_syncUpdatePeriod = new object();

        private void RaiseRefreshPeriodChanged()
        {
            CommonGlobal.RaiseEventHandler( this.m_UpdatePeriodChangedEH, new object[] { this, EventArgs.Empty }, this.m_syncUpdatePeriod );
        }

        public bool IsWorking
        {
            get { return (this.m_timer != null); }
        }

        /// <summary>
        /// Start periodical updates
        /// </summary>
        public void Start()
        {
            if( this.m_timer != null ) return;

            System.Threading.TimerCallback handler = delegate { this.UpdateData(); };
            this.m_timer = new System.Threading.Timer( handler, null, new TimeSpan(), this.UpdatePeriod );

            //for refresh stores cach and connections
            this.UpdatePeriodChanged += delegate { this.m_timer.Change( TimeSpan.Zero, this.UpdatePeriod ); };
        }
        /// <summary>
        /// Stop periodical updates
        /// </summary>
        public void Stop()
        {
            if( this.m_timer == null )
                return;

            this.m_timer.Dispose();
        }
        /// <summary>
        /// Update actions
        /// </summary>
        protected abstract void UpdateData();

        public void Update()
        {
            try
            {
                this.RaiseBeginUpdate();
                this.UpdateData();
            }
            finally
            {
                this.RaiseEndUpdate();
            }
        }

        #region event BeginUpdate

        public event EventHandler BeginUpdate
        {
            add { lock( this.m_syncBeginUpdate ) { this.m_OnBeginUpdateEH += value; } }
            remove { lock( this.m_syncBeginUpdate ) { this.m_OnBeginUpdateEH -= value; } }
        }
        private EventHandler m_OnBeginUpdateEH = null;
        private readonly object m_syncBeginUpdate = new object();

        private void RaiseBeginUpdate()
        {
            CommonGlobal.RaiseEventHandler( this.m_OnBeginUpdateEH, new object[] { this, EventArgs.Empty }, this.m_syncBeginUpdate );
        }

        #endregion event BeginUpdate

        #region event EndUpdate

        public event EventHandler EndUpdate
        {
            add { lock( this.m_syncEndUpdate ) { this.m_OnEndUpdateEH += value; } }
            remove { lock( this.m_syncEndUpdate ) { this.m_OnEndUpdateEH -= value; } }
        }
        private EventHandler m_OnEndUpdateEH = null;
        private readonly object m_syncEndUpdate = new object();

        private void RaiseEndUpdate()
        {
            CommonGlobal.RaiseEventHandler( this.m_OnEndUpdateEH, new object[] { this, EventArgs.Empty }, this.m_syncEndUpdate );
        }

        #endregion event EndUpdate

        #region IDisposable Members

        public virtual void Dispose()
        {
            this.Stop();
        }

        #endregion
    }
}
